//
//  r1.c
//
//
//  Created by Brandon Strickland on 2/7/13.
//
//
//
//things to change:
//
//
//
//

#include <stdlib.h>
#include <stdio.h>
#include "r1.h"
#include "mpx_supt.h"

int dir(int argc, char *argv[])
{
	char currentDir[2];
	char cannotOpenDir[50];
	char fileName[50];
	char temp[50];
	int cannotOpenDirSize;
	int fileNameSize;
	long fileSize;

	strcpy(currentDir, "\0");
	strcpy(cannotOpenDir, "We couldn't open the directory\n");
	strcpy(fileName, "null");
	strcpy(temp, "yes");
	cannotOpenDirSize = strlen(cannotOpenDir);
	fileSize = 0;
	fileNameSize = 50;

	if(strcmp(argv[0], "ls") != 0)
	{
		return 0;
	}
	else
	{
		if(argc==1)
		{
			if(sys_open_dir("\0")==ERR_SUP_DIROPN)
			{
				sys_req(WRITE,TERMINAL,cannotOpenDir,&cannotOpenDirSize);
			}
			else
			{
				while(sys_get_entry(fileName,fileNameSize,&fileSize)!=-113)
				{
					sprintf(temp, " %.2f\n",fileSize);
					strcat(fileName, temp);
					printf(fileName);
					//sys_req(WRITE,TERMINAL,fileName,&fileNameSize);
				}
				sys_close_dir();
			}
			return 1;
		}
		else
		{
			if(sys_open_dir(argv[1])==ERR_SUP_DIROPN)
			{
				sys_req(WRITE,TERMINAL,cannotOpenDir,&cannotOpenDirSize);
			}
			else
			{
				while(sys_get_entry(fileName,fileNameSize,&fileSize)!=-113)
				{
					sprintf(temp, " %.2f\n",fileSize);
					strcat(fileName, temp);
					printf(fileName);
					//sys_req(WRITE,TERMINAL,fileName,&fileNameSize);
				}
				sys_close_dir();
			}
			return 1;
		}
	}
}

//Author: Billy Badass
//Date: 2/7/13
//
//in driver, this is called if the last function is called since no other
//function returned 1.
//
//this shouldn't ever need to be changed(i dont see any reason)
int invalid(int argc, char *argv[])
{
	char invalidStatement[40];
	int statementSize;

	argv++;//avoid compiler warnings of never being used
	argc++;//same
	sprintf(invalidStatement, "Invalid Statement\n");
	statementSize = strlen(invalidStatement);
	sys_req(WRITE, TERMINAL, invalidStatement, &statementSize);

	return TRUE;
}


int date(int argc, char *argv[]) {
  char dateString[60], invalidStatement[60], badDate[60];
  int success, dateLength, invalidLength, badDateLength;
  date_rec date;
  if(strcmp(argv[0], "date") != 0)
    return FALSE;
  sprintf(invalidStatement, "Invalid date command\n");
  invalidLength = strlen(invalidStatement);
  sprintf(badDate, "Invalid date\n");
  badDateLength = strlen(badDate);
  switch(argc) {
  case 1:
    sys_get_date(&date);
    dateToString(date, dateString);
    dateLength = strlen(dateString);
    sys_req(WRITE, TERMINAL, dateString, &dateLength);
    break;
  case 2:
    success = stringToDate(&date, argv[1]);
    if(success) {
      sys_set_date(&date);
    } else sys_req(WRITE, TERMINAL, badDate, &badDateLength);
    break;
  default:
    sys_req(WRITE, TERMINAL, invalidStatement, &invalidLength);
  }
  return TRUE;
}

void dateToString(date_rec date, char *out) {
  sprintf(out, "The current system date is %i-%i-%i\n", date.month, date.day, date.year);
}

int stringToDate(date_rec *date, char *in) {
  char *token;
  token = strtok(in, "-/.");
  if(!assign(token, &date->month))
    return FALSE;
  token = strtok(NULL, "-/.");
  if(!assign(token, &date->day))
    return FALSE;
  token = strtok(NULL, "-/.");
  if(!assign(token, &date->year))
    return FALSE;
  return check(*date);
}

int assign(char *buff, int *set) {
  int i;
  i = atoi(buff);
  if(i) {
    *set = i;
    return TRUE;
  }
  return FALSE;
}

int check(date_rec date) {
  int b;
  if(date.month>12)
    return FALSE;
  switch(date.month) {
  case 2:
    if(date.year % 4 == 0) {
      if(date.year % 25 == 0)
	    b = 28;
      else b = 29;
    } else b = 28;
    break;
  case 4:
  case 6:
  case 9:
  case 11:
    b = 30;
    break;
  case 1:
  case 3:
  case 5:
  case 7:
  case 8:
  case 10:
  case 12:
    b = 31;
    break;
  }
  if(date.day <= b)
    return TRUE;
  return FALSE;
}

/*
  Function:Version
  The purpose of this function is to display the current
  version of the mpx project and the date that of the
  last modification made.
*/
int version(int argc, char *argv[]) {
  char current_version[60], invalid[60];
  char date[60];
  int size;
  if(strcmp(argv[0], "version") != 0)
    return FALSE;
  sprintf(invalid, "Invalid version command\n");
  size = strlen(invalid);
  if(argc != 1) {
    sys_req(WRITE, TERMINAL, invalid, &size);
    return TRUE;
  }
  sprintf(current_version, "Version: %.1f\nLast Modification: %i/%i/%i.\n", VERSION, MONTH, DAY, YEAR);
  size = strlen(current_version);
  sys_req(WRITE, TERMINAL, current_version, &size);
  return TRUE;
}

//Chad Rothermund
//2/7/13
//Checks the user actually wants to quit, then cleanly exits the program and frees allocated memory.
//Preconditions: argv contains one element which is "exit"
//Postconditions: System exits when appropriate
int quit(int argc, char *argv[])
{
	char a[64];
	int x;
	int size, sizeInv;
	char message[60], invalidMessage[60];

	x = 0;
	strcpy(invalidMessage, "Invalid exit command\n");
	strcpy(message, "Are you sure you want to quit? (Enter y/n)\n");
	size = strlen(message);
	sizeInv = strlen(invalidMessage);

	if(strcmp(argv[0], "exit") == 0)
	{
		if(argc != 1)
		{
			sys_req(WRITE, TERMINAL, invalidMessage, &sizeInv);
			x = 1;
		}
		else
		{
			sys_req(WRITE, TERMINAL, message, &size);
			size = 63;
			sys_req(READ, TERMINAL, a, &size);
			if(a[0]=='y')
			{ //If the user types a yes, proceed to exit.
			  //free memory which hasn't been allocated yet
				x = -1;
			}
			else if(a[0]=='n')
			{
				x = 1;
			}
			else
			{
				x = 0;
			}
		}
	}
	else
	{  //If the user types anything else, return to the loop.
		x = 0;
	}

	return x;
}

int help(int argc, char *argv[])
{
	char invalid[50], displayText[100];
	int dispSize;

	if(strcmp(argv[0], "help") != 0)
		return FALSE;

	strcpy(invalid, "Invalid help command. Type \"help\" for help\n");

	if(argc > 2)
	{
		strcpy(displayText, invalid);
	} else if(argc == 1)
	{
		strcpy(displayText, "List of Commands:\n-date\n-version\n-ls\n-help\n-exit\nType in help then the name of the command (eg. help date) for further help\n");
	}
	else
	{
		if(strcmp(argv[1], "date") == 0)
		{
			printf("Date:\n=====\n-type \"date\" to get the current date\n-type \"date mm-dd-yyyy\" to set the date\n-you could use other date formats as \"mm.dd.yyyy\" or \"mm/dd/yyyy\"\n-any other format will not work.\n");
			strcpy(displayText, "");
		}
		else if(strcmp(argv[1], "exit") == 0)
		{
			strcpy(displayText, "Exit:\n=====\nExits the system.\n");
		}
		else if(strcmp(argv[1], "help") == 0)
		{
			strcpy(displayText, "Help:\n=====\nOpens a help menu for the user.\n");
		}
		else if(strcmp(argv[1], "version") == 0)
		{
			strcpy(displayText, "Version:\n========\nDisplays current version of system and last modified date.\n");
		}
		else if(strcmp(argv[1], "ls") == 0)
		{
			strcpy(displayText, "Display Directory:\n==================\nThis command shows all the files in the current directory, and the size of the file.\n");
		}
		else if(strcmp(argv[1], "createPCB") == 0)
		{
			strcpy(displayText, "This creates a PCB with the second word being the name followed by the sys or app class then by the priority\n");
		}
		else if(strcmp(argv[1], "deletePCB") )
		{
			strcpy(displayText, "the proper sytax is deletePCB followed by the name of the PCB. It will be removed from the queue it is in and deleted\n");
		}
		else if( strcmp(argv[1], "blockPCB" ) )
		{
			strcpy(displayText, "the proper syntax is blockPCB followed by the name of the PCB you want to send to the blocked queue.\n");
		}
		else if( strcmp(argv[1], "unblockedPCB") )
		{
			strcpy(displayText, "unblockPCB has a simply syntax. unblockPCB followed by the name of that PCB to remove it from the blocked queue to the ready queue\n");
		}
		else if( strcmp(argv[1], "suspendPCB") )
		{
			strcpy(displayText, "suspendPCB is an easy command to run. simply put suspendPCB followed by the name of the PCB\n");
		}
		else if( strcmp(argv[1], "resumePCB") )
		{
			strcpy(displayText, "resumePCB is easy to use like the others. resumePCB followed by the name of the PCB to move it back to a ready type queue.\n");
		}
		else if( strcpy(argv[1], "setPCBPriority") )
		{
			strcpy(displayText, "set PCB priority cahnges the priority it would have in a queue. you can use this command as setPCBPriority followed by then name then by the new value of the priority as long as it is between -128 and 127.\n");
		}
		else if( strcpy(argv[1], "showPCB") )
		{
			strcpy(displayText, "the showPCB command shows you a specific PCB you choose. showPCB followed by the name of the PCB is the correct syntax for this command.\n");
		}
		else if( strcpy(argv[1], "showReady") )
		{
			strcpy( displayText, "showReady simply displays all the PCB in FIFO's.\n");
		}
		else if( strcpy(argv[1], "showBlocked") )
		{
			strcpy( displayText, "showBlocked simply displats all the CBs in the queue in FIFO.\n");
		}
		else
		{
			strcpy(displayText, invalid);
		}
	}
	dispSize = strlen(displayText);
	sys_req(WRITE, TERMINAL, displayText, &dispSize);
	return TRUE;
}

